//
// Created by guo on 24-8-15.
//

#include "Blackboard.h"
#include <unordered_map>
#include <condition_variable>
#include <mutex>
#include <iostream>
#include "../common/shared_locker.h"

class NotifyCV{
public:
    std::mutex _mutex;
    std::condition_variable _cv;
};

class BlackboardPrivate{
public:
    BlackboardPrivate()= default;

    //用于memory notify/wait黑板
    std::unordered_map<std::string, NotifyCV*> _notify_map;
    std::unordered_map<std::string, std::string> _notify_map_data;
    SharedLocker _notify_map_data_locker;
    SharedLocker _notify_map_locker;

    //用于memory set/get黑板
    std::unordered_map<std::string, std::string> _map_data;
    SharedLocker _map_data_locker;
};

static BlackboardPrivate* _p = new BlackboardPrivate;

Blackboard::Blackboard() {

}

Blackboard::~Blackboard() {

}

bool Blackboard::set_memory_bb(const std::string &key, const std::string &value) {
    _p->_map_data_locker.lock();
    if(_p->_map_data.find(key) == _p->_map_data.end()){
        _p->_map_data.insert(std::make_pair(key, value));
    }else{
        _p->_map_data[key] = value;
    }
    _p->_map_data_locker.unlock();
    return true;
}

bool Blackboard::get_memory_bb(const std::string &key, std::string &value) {
    _p->_map_data_locker.lock_shared();
    auto it = _p->_map_data.find(key);
    if(it != _p->_map_data.end()){
        value = it->second;
        _p->_map_data_locker.unlock_shared();
        return true;
    }else{
        value.clear();
        _p->_map_data_locker.unlock_shared();
        return false;
    }
}

void Blackboard::erase_memory_bb(const std::string &key) {
    _p->_map_data_locker.lock();
    _p->_map_data.erase(key);
    _p->_map_data_locker.unlock();
}

void Blackboard::notify_memory_bb(const std::string &key, const std::string &value) {
    auto it = _p->_notify_map.find(key);
    if(it != _p->_notify_map.end()){
        if(_p->_notify_map_data.find(key) == _p->_notify_map_data.end()){
            _p->_notify_map_data.insert(std::make_pair(key, value));
        }else{
            _p->_notify_map_data[key] = value;
        }
        it->second->_cv.notify_all();
    }else{
        std::cout << "notify failed" << std::endl;
    }
}

bool Blackboard::wait_memory_bb(const std::string &key, std::string &value) {
    bool ret = false;
    _p->_notify_map_locker.lock();
    auto it = _p->_notify_map.find(key);
    if(it == _p->_notify_map.end()){
        auto data = new NotifyCV;
        _p->_notify_map.insert(std::make_pair(key,data));
        it = _p->_notify_map.find(key);
    }
    _p->_notify_map_locker.unlock();
    std::unique_lock<std::mutex> locker(it->second->_mutex);
    it->second->_cv.wait(locker);

    _p->_notify_map_data_locker.lock_shared();
    auto it_data = _p->_notify_map_data.find(key);
    if(it_data != _p->_notify_map_data.end()){
        value = _p->_notify_map_data[key];
        ret = true;
    }else{
        ret = false;
    }
    _p->_notify_map_data_locker.unlock_shared();
    return ret;
}

bool Blackboard::set_speaker_bb(const std::string &key, const std::string &value) {
    return false;
}

bool Blackboard::get_speaker_bb(const std::string &key, std::string &value) {
    return false;
}

bool Blackboard::set_conference_bb(const std::string &key, const std::string &value) {
    return false;
}

bool Blackboard::get_conference_bb(const std::string &key, std::string &value) {
    return false;
}